package com.teamblueplus.comicmaker;

import java.io.IOException;

import android.content.Context;
import android.graphics.*;
import android.media.ExifInterface;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;

import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.teamblueplus.brush.PaintBrush;

/**
 * SurfaceView for draw and crop on selected image
 * 
 * @author qui
 * 
 */
public class ImageEditorSurfaceView extends SurfaceView implements
		SurfaceHolder.Callback {
	private Boolean _run;
	protected DrawThread thread;
	private Bitmap mBitmap;
	public boolean isDrawing = true;
	// delete later
	// public DrawingPath previewPath;

	public Bitmap _objectBitmap;

	public PaintBrush brush2;

	private int sviewWidth, sviewHeight, bottomPadding, topPadding;
	private String imagePath;
	// use when image came from gallery, cause the image is displayed
	// horizontally
	static private boolean rotateImage;
	private static int origImageWidth;
	private static int origImageHeight;

	// use when crop is used
	public Bitmap _croppedBitmap;
	public boolean isCropped = false;

	private int posX, posY;

	public boolean isObjectBitmapInit = false;

	public ImageEditorSurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);

		// set the bottom padding to 20px
		bottomPadding = 20;

		getHolder().addCallback(this);

		brush2 = new PaintBrush();

		thread = new DrawThread(getHolder());
	}

	private Handler previewDoneHandler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			Log.d("draw", "handleMessage is Drawing FALSE");
			// isDrawing = false;
		}
	};

	class DrawThread extends Thread {
		private SurfaceHolder mSurfaceHolder;

		public DrawThread(SurfaceHolder surfaceHolder) {
			mSurfaceHolder = surfaceHolder;

		}

		public void setRunning(boolean run) {
			_run = run;

		}

		@Override
		public void run() {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			Canvas c = null;
			while (_run) {
				if (isDrawing == true) {
					try {

						c = mSurfaceHolder.lockCanvas(null);
						synchronized (mSurfaceHolder) {
							draw(c);
						}

					} finally {
						if (c != null){
							mSurfaceHolder.unlockCanvasAndPost(c);
						// isDrawing = false;
						}
					}
				}
			}
		}
	}

	public void draw(Canvas canvas) {
		// for changing of activity, pause, resume
		if (canvas == null) {
			return;
		}

		if (mBitmap == null) {
			mBitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
		}

		// we created another canvas with bitmap as parameter so
		// the canvas
		// will be draw into the bitmap, the bitmap will be use
		// to save all
		// the drawings when we save it to a file.
		final Canvas c = new Canvas(mBitmap);

		// draw black background
		c.drawColor(Color.BLACK);

		if (isObjectBitmapInit) {

		}

		// draw the image
		if (_objectBitmap != null) {
			c.drawBitmap(_objectBitmap, posX, posY, null);
		}

		// brush2
		brush2.executeAll(c, previewDoneHandler);
		// draw the preview path
		c.drawPath(brush2.currentDrawingPath.path,
				brush2.currentDrawingPath.paint);

		// this canvas just display the bitmaps on the screen

		canvas.drawBitmap(mBitmap, 0, 0, null);
	}

	public Bitmap getBitmap() {

		return _objectBitmap;
	}

	public Bitmap getOrigDimBitmap() {

		Bitmap compressBitmap = Bitmap.createScaledBitmap(_objectBitmap,
				origImageWidth, origImageHeight, false);
		return compressBitmap;
	}

	public void pause() {
	}

	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {

		mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

		Log.d("draw", "surfaceChanged");
		Log.d("draw", "width::" + width);
		Log.d("draw", "height::" + height);

		sviewHeight = height;
		sviewWidth = width;

		if (this.imagePath != null) {
			// if image is cropped
			if (!isCropped) {
				Log.d("h2", "surfaceCreate::NotCrop");
				_objectBitmap = ImageEditorSurfaceView
						.decodeSampledBitmapFromFile(imagePath, width, height);
			} else {
				_objectBitmap = _croppedBitmap;
				Log.d("h2", "surfaceCreate::Cropped");
			}

			this.setPosition(width, height, _objectBitmap.getWidth(),
					_objectBitmap.getHeight());
		} else
			_objectBitmap = null;

	}

	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		Log.d("h2", "imagePathINSurfaceChange::" + imagePath);

		thread = new DrawThread(getHolder());

		isDrawing = true;
		thread.setRunning(true);
		thread.start();
		Log.d("draw", "surfaceCreated");

	}

	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		Log.d("draw", "surfaceDestroyed");

		this.isDrawing = false;
		this.thread.setRunning(false);
		boolean retry = true;
		while (retry) {
			try {
				thread.join();
				retry = false;
			} catch (InterruptedException e) {
				Log.v("pause()", e.toString());
			}
			break;
		}

		this.thread.mSurfaceHolder = null;
		this.thread = null;
		
		if (mBitmap != null){
			this.mBitmap.recycle();
		}
		if (_objectBitmap != null) {
			this._objectBitmap.recycle();
		}
	}

	public void setPosition(int width, int height, int imgWidth, int imgHeight) {

		int diff = width - imgWidth;
		this.posX = (int) (diff / 2.0);

		diff = height - imgHeight;
		this.posY = (int) (diff / 2.0);

	}

	public static int calculateInSampleSize(BitmapFactory.Options options,
			int reqWidth, int reqHeight) {
		// Raw height and width of image
		final int height = options.outHeight;
		final int width = options.outWidth;

		origImageWidth = options.outWidth;
		origImageHeight = options.outHeight;

		int inSampleSize = 1;

		if (height > reqHeight || width > reqWidth) {
			if (width > height) {
				inSampleSize = Math.round((float) height / (float) reqHeight);
			} else {
				inSampleSize = Math.round((float) width / (float) reqWidth);
			}
		}
		return inSampleSize;
	}

	public static Bitmap decodeSampledBitmapFromFile(String path, int reqWidth,
			int reqHeight) {

		// First decode with inJustDecodeBounds=true to check dimensions
		final BitmapFactory.Options options = new BitmapFactory.Options();
		options.inJustDecodeBounds = true;
		Bitmap bm = BitmapFactory.decodeFile(path, options);
		Log.d("h2", "origWidth::" + options.outWidth);
		Log.d("h2", "origHeigth::" + options.outHeight);
		// Calculate inSampleSize
		options.inSampleSize = calculateInSampleSize(options, reqWidth,
				reqHeight);

		// Decode bitmap with inSampleSize set
		options.inJustDecodeBounds = false;

		Log.d("h2", "inSampleSize::" + options.inSampleSize);
		Bitmap temp = BitmapFactory.decodeFile(path, options);

		// check orientation of image
		int orientation = 0;
		try {
			ExifInterface exif = new ExifInterface(path);
			orientation = exif
					.getAttributeInt(ExifInterface.TAG_ORIENTATION, 1);
		} catch (IOException e) {
			e.printStackTrace();
		}

		Log.d("h2", "orientation::" + orientation);

		if (ImageEditorSurfaceView.rotateImage && orientation == 6) {

			final Matrix matrix = new Matrix();
			matrix.postRotate(90);
			Bitmap temp2 = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(),
					temp.getHeight(), matrix, true);
			int xy[] = calculateAspectRatio(reqWidth, reqHeight,
					temp2.getWidth(), temp2.getHeight());
			Bitmap temp3 = Bitmap
					.createScaledBitmap(temp2, xy[0], xy[1], false);
			return temp3;

		} else if (ImageEditorSurfaceView.rotateImage && orientation == 3) {

			final Matrix matrix = new Matrix();
			matrix.postRotate(180);
			Bitmap temp2 = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(),
					temp.getHeight(), matrix, true);
			int xy[] = calculateAspectRatio(reqWidth, reqHeight,
					temp2.getWidth(), temp2.getHeight());
			Bitmap temp3 = Bitmap
					.createScaledBitmap(temp2, xy[0], xy[1], false);
			return temp3;

		} else if (ImageEditorSurfaceView.rotateImage && orientation == 8) {

			final Matrix matrix = new Matrix();
			matrix.postRotate(270);
			Bitmap temp2 = Bitmap.createBitmap(temp, 0, 0, temp.getWidth(),
					temp.getHeight(), matrix, true);
			int xy[] = calculateAspectRatio(reqWidth, reqHeight,
					temp2.getWidth(), temp2.getHeight());
			Bitmap temp3 = Bitmap
					.createScaledBitmap(temp2, xy[0], xy[1], false);
			return temp3;

		} else {
			int[] xy = calculateAspectRatio(reqWidth, reqHeight,
					temp.getWidth(), temp.getHeight());
			Bitmap temp2 = Bitmap.createScaledBitmap(temp, xy[0], xy[1], false);
			return temp2;
		}
	}

	public static int[] calculateAspectRatio(int winWidth, int winHeight,
			int imgWidth, int imgHeight) {
		float img_ratio = (float) imgWidth / (float) imgHeight;
		float win_ratio = (float) winWidth / (float) winHeight;
		int[] xy = new int[2];

		if (img_ratio == win_ratio) {
			xy[0] = winWidth;
			xy[1] = winHeight;
		} else if (img_ratio > win_ratio) {
			xy[0] = winWidth;
			xy[1] = (int) ((float) winWidth / img_ratio);
		} else {
			xy[0] = (int) ((float) winHeight * img_ratio);
			xy[1] = winHeight;
		}
		return xy;
	}

	public int getPageWidth() {
		return this.sviewWidth;
	}

	public int getPageHeight() {
		return this.sviewHeight - this.bottomPadding;
	}

	public int getTopPadding() {
		return this.topPadding;
	}

	public void setImagePath(String path, boolean rotate) {
		this.imagePath = path;
		rotateImage = rotate;
	}

}